diff --git a/Changelog.md b/Changelog.md
index d464cbe..9c68ef0 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -9,6 +9,8 @@ This file holds the changelog for Pepperminty Wiki. This is the master list of t
      - Added action `stats` to view the calculated statisics
      - Statistics are automagically recalculated every day - this can be controlled with the `stats_update_interval` and `stats_update_processingtime` settings
  - Added new "« Parent Page" to subpages so that you can easily visit their parent pages
+ - Users can now delete their own comments, and users logged in as a moderator or better can delete anyone's comments.
+     - Added new `comment-delete` action
  - The `history` action now supports `format=json` and `format=csv`
  - Added tags next to the names of pages in the search results
  - Added new `random_page_exclude` setting that allows you to exclude pages from the random action with a (PHP) regular expression
diff --git a/build/index.php b/build/index.php
index 0931e83..0b73754 100644
--- a/build/index.php
+++ b/build/index.php
@@ -366,6 +366,7 @@ summary { cursor: pointer; }
 .comment-body { padding: 0 1em; }
 .comment-footer { padding-left: 1em; }
 .comment-footer-item { padding: 0 0.3em; }
+.comment-footer .delete-button { -moz-appearance: button; -webkit-appearance: button; text-decoration: none; color: #514C4C; }
 .permalink-button { text-decoration: none; }
 .comments-list .comments-list .comment { margin: 1em; }
 
@@ -2643,6 +2644,70 @@ register_module([
 			exit(page_renderer::render_main("Comment posted successfully - $settings->sitename", "<p>Your comment on $env->page was posted successfully. If your browser doesn't redirect you automagically, please <a href='?action=view&page=" . rawurlencode($env->page) . "commentsuccess=yes#comment-$new_comment->id'>click here</a> to go to the comment you posted on the page you were viewing.</p>"));
 		});
 		
+		
+		/**
+		 * @api {post} ?action=comment-delete&page={page_name}&delete_id={id_to_delete}	Delete a comment
+		 * @apiName CommentDelete
+		 * @apiGroup Comment
+		 * @apiPermission User
+		 * @apiDescription	Deletes a comment with the specified id. If you aren't the one who made the comment in the first place, then you must be a moderator or better to delete it.
+		 * 
+		 * @apiUse		PageParameter
+		 * @apiParam	{string}	delete_id	The id of the comment to delete.
+		 * 
+		 * @apiError	CommentNotFound	The comment to delete was not found.
+		 */
+		
+		/*
+		 *  ██████  ██████  ███    ███ ███    ███ ███████ ███    ██ ████████
+		 * ██      ██    ██ ████  ████ ████  ████ ██      ████   ██    ██
+		 * ██      ██    ██ ██ ████ ██ ██ ████ ██ █████   ██ ██  ██    ██ █████
+		 * ██      ██    ██ ██  ██  ██ ██  ██  ██ ██      ██  ██ ██    ██
+		 *  ██████  ██████  ██      ██ ██      ██ ███████ ██   ████    ██
+		 * ██████  ███████ ██      ███████ ████████ ███████
+		 * ██   ██ ██      ██      ██         ██    ██
+		 * ██   ██ █████   ██      █████      ██    █████
+		 * ██   ██ ██      ██      ██         ██    ██
+		 * ██████  ███████ ███████ ███████    ██    ███████
+		 */
+		add_action("comment-delete", function () {
+			global $env, $settings;
+			
+			
+			if(!isset($_GET["delete_id"])) {
+				http_response_code(400);
+				exit(page_renderer::render_main("Error - Deleting Comment - $settings->sitename", "<p>You didn't specify the id of a comment to delete.</p>"));
+			}
+			
+			// Make sure that the user is logged in before deleting a comment
+			if(!$env->is_logged_in) {
+				http_response_code(307);
+				header("location: ?action=login&returnto=" . rawurlencode("?action=comment-delete&page=" . rawurlencode($env->page) . "&id=" . rawurlencode($_GET["delete_id"])));
+			}
+			
+			$comment_filename = get_comment_filename($env->page);
+			$comments = json_decode(file_get_contents($comment_filename));
+			$target_id = $_GET["delete_id"];
+			
+			$comment_to_delete = find_comment($comments, $target_id);
+			if($comment_to_delete->username !== $env->user && !$env->is_admin) {
+				http_response_code(401);
+				exit(page_renderer::render_main("Error - Deleting Comment - $settings->sitename", "<p>You can't delete the comment with the id <code>" . htmlentities($target_id) . "</code> on the page <em>$env->page</em> because you're logged in as " . page_renderer::render_username($env->user) . ", and " . page_renderer::render_username($comment_to_delete->username) . " made that comment. Try <a href='?action=logout'>Logging out</a> and then logging in again as " . page_renderer::render_username($comment_to_delete->username) . ", or as a moderator or better."));
+			}
+			
+			if(!delete_comment($comments, $_GET["delete_id"])) {
+				http_response_code(404);
+				exit(page_renderer::render_main("Comment not found - Deleting Comment - $settings->sitename", "<p>The comment with the id <code>" . htmlentities($_GET["delete_id"]) . "</code> on the page <em>$env->page</em> wasn't found. Perhaps it was already deleted?</p>"));
+			}
+			
+			if(!file_put_contents($comment_filename, json_encode($comments))) {
+				http_response_code(503);
+				exit(page_renderer::render_main("Server Error - Deleting Comment - $settings->sitename", "<p>While $settings->sitename was able to delete the comment with the id <code>" . htmlentities($target_id) . "</code> on the page <em>$env->page</em>, it couldn't save the changes back to disk. Please contact <a href='mailto:" . hide_email($settings->admindetails_email) . "'>$settings->admindetails_name</a>, $settings->sitename's local friendly administrator about this issue.</p>"));
+			}
+			
+			exit(page_renderer::render_main("Comment Deleted - $settings->sitename", "<p>The comment with the id <code>" . htmlentities($target_id) . "</code> on the page <em>$env->page</em> has been deleted successfully. <a href='?page=" . rawurlencode($env->page) . "&redirect=no'>Go back</a> to " . htmlentities($env->page) . ".</p>"));
+		});
+		
 		if($env->action == "view") {
 			page_renderer::register_part_preprocessor(function(&$parts) {
 				global $env;
@@ -2775,6 +2840,31 @@ function find_comment($comment_data, $comment_id)
 	return false;
 }
 
+/**
+ * Deletes the first comment found with the specified id.
+ * @param	array	$comment_data	An array of threaded comments to delete the comment from.
+ * @param	string	$target_id		The id of the comment to delete.
+ * @return	bool					Whether the comment was found and deleted or not.
+ */
+function delete_comment(&$comment_data, $target_id)
+{
+	$comment_count = count($comment_data);
+	if($comment_count === 0) return false;
+	
+	for($i = 0; $i < $comment_count; $i++) {
+		if($comment_data[$i]->id == $target_id) {
+			$comment_data[$i]->message = "_[Deleted]_";
+			return true;
+		}
+		if(count($comment_data[$i]->replies) > 0 &&
+			delete_comment($comment_data[$i]->replies, $target_id))
+			return true;
+	}
+	
+	
+	return false;
+}
+
 /**
  * Fetches all the parent comments of the specified comment id, including the
  * comment itself at the end.
@@ -2817,7 +2907,7 @@ function fetch_comment_thread($comment_data, $comment_id)
  */
 function render_comments($comments_data, $depth = 0)
 {
-	global $settings;
+	global $settings, $env;
 	
 	if(count($comments_data) == 0) {
 		if($depth == 0)
@@ -2840,6 +2930,8 @@ function render_comments($comments_data, $depth = 0)
 		$result .= "\t<div class='reply-box-container'></div>\n";
 		$result .= "\t<p class='comment-footer'>";
 		$result .= "\t\t<span class='comment-footer-item'><button class='reply-button'>Reply</button></span>\n";
+		if($env->user == $comment->username || $env->is_admin)
+			$result .= "<span class='comment-footer-item'><a href='?action=comment-delete&page=" . rawurlencode($env->page) . "&delete_id=" . rawurlencode($comment->id) . "' class='delete-button'>Delete</a></span>\n";
 		$result .= "\t\t<span class='comment-footer-item'><a class='permalink-button' href='#comment-$comment->id' title='Permalink to this comment'>&#x1f517;</a></span>\n";
 		$result .= "\t\t<span class='comment-footer-item'><time datetime='" . date("c", strtotime($comment->timestamp)) . "' title='The time this comment was posted'>$settings->comment_time_icon " . date("l jS \of F Y \a\\t h:ia T", strtotime($comment->timestamp)) . "</time></span>\n";
 		$result .= "\t</p>\n";
@@ -8261,7 +8353,7 @@ foreach($remote_files as $remote_file_def) {
 	if(file_exists($remote_file_def["local_filename"]) && filesize($remote_file_def["local_filename"]) > 0)
 		continue;
 	
-	error_log("[Pepperminty-Wiki/$settings->sitename] Downloading {$remote_file_def["local_filename"]} from {$remote_file_def["remote_url"]}");
+	error_log("[ Pepperminty-Wiki/$settings->sitename ] Downloading {$remote_file_def["local_filename"]} from {$remote_file_def["remote_url"]}");
 	file_put_contents($remote_file_def["local_filename"], fopen($remote_file_def["remote_url"], "rb"));
 }
 
diff --git a/module_index.json b/module_index.json
index 182461e..111d8d9 100755
--- a/module_index.json
+++ b/module_index.json
@@ -59,7 +59,7 @@
         "author": "Starbeamrainbowlabs",
         "description": "Adds threaded comments to the bottom of every page.",
         "id": "feature-comments",
-        "lastupdate": 1505513014,
+        "lastupdate": 1511092311,
         "optional": false
     },
     {
diff --git a/modules/feature-comments.php b/modules/feature-comments.php
index 1041f72..af4b9f1 100644
--- a/modules/feature-comments.php
+++ b/modules/feature-comments.php
@@ -129,6 +129,70 @@ register_module([
 			exit(page_renderer::render_main("Comment posted successfully - $settings->sitename", "<p>Your comment on $env->page was posted successfully. If your browser doesn't redirect you automagically, please <a href='?action=view&page=" . rawurlencode($env->page) . "commentsuccess=yes#comment-$new_comment->id'>click here</a> to go to the comment you posted on the page you were viewing.</p>"));
 		});
 		
+		
+		/**
+		 * @api {post} ?action=comment-delete&page={page_name}&delete_id={id_to_delete}	Delete a comment
+		 * @apiName CommentDelete
+		 * @apiGroup Comment
+		 * @apiPermission User
+		 * @apiDescription	Deletes a comment with the specified id. If you aren't the one who made the comment in the first place, then you must be a moderator or better to delete it.
+		 * 
+		 * @apiUse		PageParameter
+		 * @apiParam	{string}	delete_id	The id of the comment to delete.
+		 * 
+		 * @apiError	CommentNotFound	The comment to delete was not found.
+		 */
+		
+		/*
+		 *  ██████  ██████  ███    ███ ███    ███ ███████ ███    ██ ████████
+		 * ██      ██    ██ ████  ████ ████  ████ ██      ████   ██    ██
+		 * ██      ██    ██ ██ ████ ██ ██ ████ ██ █████   ██ ██  ██    ██ █████
+		 * ██      ██    ██ ██  ██  ██ ██  ██  ██ ██      ██  ██ ██    ██
+		 *  ██████  ██████  ██      ██ ██      ██ ███████ ██   ████    ██
+		 * ██████  ███████ ██      ███████ ████████ ███████
+		 * ██   ██ ██      ██      ██         ██    ██
+		 * ██   ██ █████   ██      █████      ██    █████
+		 * ██   ██ ██      ██      ██         ██    ██
+		 * ██████  ███████ ███████ ███████    ██    ███████
+		 */
+		add_action("comment-delete", function () {
+			global $env, $settings;
+			
+			
+			if(!isset($_GET["delete_id"])) {
+				http_response_code(400);
+				exit(page_renderer::render_main("Error - Deleting Comment - $settings->sitename", "<p>You didn't specify the id of a comment to delete.</p>"));
+			}
+			
+			// Make sure that the user is logged in before deleting a comment
+			if(!$env->is_logged_in) {
+				http_response_code(307);
+				header("location: ?action=login&returnto=" . rawurlencode("?action=comment-delete&page=" . rawurlencode($env->page) . "&id=" . rawurlencode($_GET["delete_id"])));
+			}
+			
+			$comment_filename = get_comment_filename($env->page);
+			$comments = json_decode(file_get_contents($comment_filename));
+			$target_id = $_GET["delete_id"];
+			
+			$comment_to_delete = find_comment($comments, $target_id);
+			if($comment_to_delete->username !== $env->user && !$env->is_admin) {
+				http_response_code(401);
+				exit(page_renderer::render_main("Error - Deleting Comment - $settings->sitename", "<p>You can't delete the comment with the id <code>" . htmlentities($target_id) . "</code> on the page <em>$env->page</em> because you're logged in as " . page_renderer::render_username($env->user) . ", and " . page_renderer::render_username($comment_to_delete->username) . " made that comment. Try <a href='?action=logout'>Logging out</a> and then logging in again as " . page_renderer::render_username($comment_to_delete->username) . ", or as a moderator or better."));
+			}
+			
+			if(!delete_comment($comments, $_GET["delete_id"])) {
+				http_response_code(404);
+				exit(page_renderer::render_main("Comment not found - Deleting Comment - $settings->sitename", "<p>The comment with the id <code>" . htmlentities($_GET["delete_id"]) . "</code> on the page <em>$env->page</em> wasn't found. Perhaps it was already deleted?</p>"));
+			}
+			
+			if(!file_put_contents($comment_filename, json_encode($comments))) {
+				http_response_code(503);
+				exit(page_renderer::render_main("Server Error - Deleting Comment - $settings->sitename", "<p>While $settings->sitename was able to delete the comment with the id <code>" . htmlentities($target_id) . "</code> on the page <em>$env->page</em>, it couldn't save the changes back to disk. Please contact <a href='mailto:" . hide_email($settings->admindetails_email) . "'>$settings->admindetails_name</a>, $settings->sitename's local friendly administrator about this issue.</p>"));
+			}
+			
+			exit(page_renderer::render_main("Comment Deleted - $settings->sitename", "<p>The comment with the id <code>" . htmlentities($target_id) . "</code> on the page <em>$env->page</em> has been deleted successfully. <a href='?page=" . rawurlencode($env->page) . "&redirect=no'>Go back</a> to " . htmlentities($env->page) . ".</p>"));
+		});
+		
 		if($env->action == "view") {
 			page_renderer::register_part_preprocessor(function(&$parts) {
 				global $env;
@@ -261,6 +325,31 @@ function find_comment($comment_data, $comment_id)
 	return false;
 }
 
+/**
+ * Deletes the first comment found with the specified id.
+ * @param	array	$comment_data	An array of threaded comments to delete the comment from.
+ * @param	string	$target_id		The id of the comment to delete.
+ * @return	bool					Whether the comment was found and deleted or not.
+ */
+function delete_comment(&$comment_data, $target_id)
+{
+	$comment_count = count($comment_data);
+	if($comment_count === 0) return false;
+	
+	for($i = 0; $i < $comment_count; $i++) {
+		if($comment_data[$i]->id == $target_id) {
+			$comment_data[$i]->message = "_[Deleted]_";
+			return true;
+		}
+		if(count($comment_data[$i]->replies) > 0 &&
+			delete_comment($comment_data[$i]->replies, $target_id))
+			return true;
+	}
+	
+	
+	return false;
+}
+
 /**
  * Fetches all the parent comments of the specified comment id, including the
  * comment itself at the end.
@@ -303,7 +392,7 @@ function fetch_comment_thread($comment_data, $comment_id)
  */
 function render_comments($comments_data, $depth = 0)
 {
-	global $settings;
+	global $settings, $env;
 	
 	if(count($comments_data) == 0) {
 		if($depth == 0)
@@ -326,6 +415,8 @@ function render_comments($comments_data, $depth = 0)
 		$result .= "\t<div class='reply-box-container'></div>\n";
 		$result .= "\t<p class='comment-footer'>";
 		$result .= "\t\t<span class='comment-footer-item'><button class='reply-button'>Reply</button></span>\n";
+		if($env->user == $comment->username || $env->is_admin)
+			$result .= "<span class='comment-footer-item'><a href='?action=comment-delete&page=" . rawurlencode($env->page) . "&delete_id=" . rawurlencode($comment->id) . "' class='delete-button'>Delete</a></span>\n";
 		$result .= "\t\t<span class='comment-footer-item'><a class='permalink-button' href='#comment-$comment->id' title='Permalink to this comment'>&#x1f517;</a></span>\n";
 		$result .= "\t\t<span class='comment-footer-item'><time datetime='" . date("c", strtotime($comment->timestamp)) . "' title='The time this comment was posted'>$settings->comment_time_icon " . date("l jS \of F Y \a\\t h:ia T", strtotime($comment->timestamp)) . "</time></span>\n";
 		$result .= "\t</p>\n";
diff --git a/theme_default.css b/theme_default.css
index 09250ae..1bc1c31 100644
--- a/theme_default.css
+++ b/theme_default.css
@@ -137,6 +137,7 @@ summary { cursor: pointer; }
 .comment-body { padding: 0 1em; }
 .comment-footer { padding-left: 1em; }
 .comment-footer-item { padding: 0 0.3em; }
+.comment-footer .delete-button { -moz-appearance: button; -webkit-appearance: button; text-decoration: none; color: #514C4C; }
 .permalink-button { text-decoration: none; }
 .comments-list .comments-list .comment { margin: 1em; }
 
